package com.axialproject.health.exchange.healthvaultppe;

import com.axialproject.health.exchange.EMF;
import com.axialproject.health.exchange.PatientManager;
import com.axialproject.health.exchange.entity.Patient;
import com.microsoft.hsg.PPEConnectionFactory;
import com.microsoft.hsg.HVAccessor;
import com.microsoft.hsg.Request;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import org.xml.sax.InputSource;


public class AfterLoginServlet extends HttpServlet {

    private static final Logger log = Logger.getLogger(AfterLoginServlet.class.getName());

    public void doGet (HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        
        String sig = req.getParameter("sig");
        // Need to validate the sig -- probably need providerName here ...

        String target = req.getParameter("target");
        if (target == null) {
            resp.setContentType("text/plain");
            resp.getWriter().println("This servlet is designed to handle HealthVault redirects");
            return;
        }
        target = target.toUpperCase();

        if ("APPAUTHSUCCESS".equals(target)) {
            HttpSession session = req.getSession();
            String finishUrl = (String) session.getAttribute("finishUrl");
            Long patientId = (Long) session.getAttribute("patientId");

            Patient hvpatient = new Patient ();

            EntityManager em = EMF.get().createEntityManager();
            try {
                String token = req.getParameter("wctoken");
                String [] personInfo = getPersonInfo(token);

                hvpatient.setToken(token);
                hvpatient.setUsername(personInfo [0]);
                hvpatient.setRecordId(personInfo [1]);
                hvpatient.setName(personInfo [2]);
                hvpatient.setAppName("healthvaultppe");
                PatientManager.savePatient(em, hvpatient);
            
            } catch (Exception e) {
                log.log(Level.SEVERE, e.getMessage(), e);
                resp.setContentType("text/plain");
                resp.getWriter().println("There is a problem");
                return;
            
            } finally {
                em.close ();
            }

            if (hvpatient.getId() == null) {
                log.severe("EM is closed but hvpatient.getId() still returns null. Data store problem??");
                resp.setContentType("text/plain");
                resp.getWriter().println("There is a problem");
                return;
            }
        
            em = EMF.get().createEntityManager();
            try {
                PatientManager.linkPatientIds(em, patientId, hvpatient.getId());

            } catch (Exception e) {
                log.log(Level.SEVERE, e.getMessage(), e);
                resp.setContentType("text/plain");
                resp.getWriter().println("There is a problem in linking this stuff");
                return;

            } finally {
                em.close ();
            }

            if (finishUrl.contains("?")) {
                resp.sendRedirect(finishUrl + "&success=1");
            } else {
                resp.sendRedirect(finishUrl + "?success=1");
            }
            return;

        } else if ("APPAUTHINVALIDRECORD".equals(target)) {
            resp.setContentType("text/plain");
            resp.getWriter().println("There is a problem with the authentication. Please quit and try again");
            return;

        } else if ("APPAUTHREJECT".equals(target)) {
            resp.setContentType("text/plain");
            resp.getWriter().println("There is a problem with the authentication. Please quit and try again");
            return;

        } else if ("HELP".equals(target)) {
            resp.setContentType("text/html");
            resp.getWriter().print(readFileAsString("/hv_help.html"));
            return;

        } else if ("HOME".equals(target)) {
            resp.setContentType("text/html");
            resp.getWriter().print(readFileAsString("/hv_home.html"));
            return;

        } else if ("PRIVACY".equals(target)) {
            resp.setContentType("text/html");
            resp.getWriter().print(readFileAsString("/hv_privacy.html"));
            return;

        } else if ("RECONCILECANCELED".equals(target)) {
            resp.setContentType("text/plain");
            resp.getWriter().println("User canceled reconcile of record");
            return;

        } else if ("RECONCILECOMPLETE".equals(target)) {
            resp.setContentType("text/plain");
            resp.getWriter().println("Reconcile of record completed");
            return;

        } else if ("RECONCILEFAILURE".equals(target)) {
            resp.setContentType("text/plain");
            resp.getWriter().println("Reconcile of record failed");
            return;

        } else if ("SELECTEDRECORDCHANGED".equals(target)) {
            resp.setContentType("text/plain");
            resp.getWriter().println("The selected record has changed");
            return;

        } else if ("SERVICEAGREEMENT".equals(target)) {
            resp.setContentType("text/html");
            resp.getWriter().print(readFileAsString("/hv_serviceagreement.html"));
            return;

        } else if ("SHARERECORDFAILED".equals(target)) {
            resp.setContentType("text/plain");
            resp.getWriter().println("Cannot share record");
            return;

        } else if ("SHARERECORDSUCCESS".equals(target)) {
            resp.setContentType("text/plain");
            resp.getWriter().println("Record shared");
            return;

        } else if ("SIGNOUT".equals(target)) {
            resp.setContentType("text/plain");
            resp.getWriter().println("You have signed out of HealthVault");
            return;

        } else {
            resp.setContentType("text/plain");
            resp.getWriter().println("This servlet is designed to handle HealthVault redirects");
            return;
        }

    }

    // 0: offline person ID
    // 1: recordId
    // 2: person name
    private String [] getPersonInfo(String token) throws Exception {
        String [] results = new String [3];

        Request request = new Request();
        request.setTtl(3600 * 8 + 300);
        request.setMethodName("GetPersonInfo");
        request.setUserAuthToken(token);

        HVAccessor accessor = new HVAccessor();
        accessor.send(request, PPEConnectionFactory.getConnection());
        InputStream is = accessor.getResponse().getInputStream();

        ByteArrayOutputStream bout = new ByteArrayOutputStream ();
        byte[] buf = new byte[1024];
        int len;
        while ((len = is.read(buf)) > 0) {
            bout.write(buf, 0, len);
        }
        byte [] xmlData = bout.toByteArray();
        is.close();
        bout.close();

        log.info (new String(xmlData));

        // XPath xpath = XPathFactory.newInstance().newXPath();
        XPathFactory factory = new org.apache.xpath.jaxp.XPathFactoryImpl();
        XPath xpath = factory.newXPath();
        results [0] = xpath.evaluate("//person-id", new InputSource(new ByteArrayInputStream (xmlData)));
        results [1] = xpath.evaluate("//record/@id", new InputSource(new ByteArrayInputStream (xmlData)));
        results [2] = xpath.evaluate("//person-info/name", new InputSource(new ByteArrayInputStream (xmlData)));

        return results;
    }

    private String readFileAsString(String fileOnClasspath) throws IOException{
        InputStream is = this.getClass().getResourceAsStream(fileOnClasspath);
        StringBuilder fileData = new StringBuilder(1000);
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        char[] buf = new char[1024];
        int numRead=0;
        while((numRead=reader.read(buf)) != -1){
            fileData.append(buf, 0, numRead);
        }
        reader.close();
        return fileData.toString();
    }

    public void doPost (HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        doGet (req, resp);
    }

}
